#include "hdcamera.h"
#include <stdio.h>
#include <iostream>
#include <cv.h>

HDCamera::HDCamera(IDeckLink *dl, std::string filename)
{
    m_deckLink = dl;
    selectedDisplayMode = bmdModeNTSC;
    pixelFormat = bmdFormat8BitYUV;

    g_timecodeFormat = bmdTimecodeRP188Any;
    snprintf(videoFilePrefix, sizeof(videoFilePrefix), "/home/haoliu/captured/%s",filename.c_str());
}

void HDCamera::run()
{
    boost::thread captureTrd(boost::bind(&HDCamera::localRun, this));
}

void HDCamera::localRun()
{
    //todo
    if (m_deckLink->QueryInterface(IID_IDeckLinkInput, (void**)&m_deckLinkInput) != S_OK)
    {
        //No Input
        return;
    }
    fprintf(stdout,"%s: Interface OK\n", videoFilePrefix);
    m_delegate = new HDDelegate(videoFilePrefix, this);
    m_deckLinkInput->SetCallback(m_delegate);
    m_deckLinkInput->EnableVideoInput(selectedDisplayMode,pixelFormat,inputFlags);
    fprintf(stdout,"%s: About to start stream\n", videoFilePrefix);
    //m_deckLinkInput->StartStreams();
    pthread_mutex_lock(&sleepMutex);
    pthread_cond_wait(&sleepCond, &sleepMutex);
    pthread_mutex_unlock(&sleepMutex);
}


HDCamera::HDDelegate::HDDelegate(char *filename, HDCamera *hdc) : m_refCount(0)
{
    frameCount = 0;
    g_maxFrames = 60;
    snprintf(m_videoFilePrefix, sizeof(m_videoFilePrefix), "%s",filename);
    m_HDC = hdc;
    pthread_mutex_init(&m_mutex, NULL);
}

HDCamera::HDDelegate::~HDDelegate()
{
    pthread_mutex_destroy(&m_mutex);
}

ULONG HDCamera::HDDelegate::AddRef(void)
{
    pthread_mutex_lock(&m_mutex);
        m_refCount++;
    pthread_mutex_unlock(&m_mutex);

    return (ULONG)m_refCount;
}

ULONG HDCamera::HDDelegate::Release(void)
{
    pthread_mutex_lock(&m_mutex);
        m_refCount--;
    pthread_mutex_unlock(&m_mutex);

    if (m_refCount == 0)
    {
        delete this;
        return 0;
    }

    return (ULONG)m_refCount;
}

HRESULT HDCamera::HDDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* videoFrame, IDeckLinkAudioInputPacket* audioFrame)
{
    IDeckLinkVideoFrame*	                rightEyeFrame = NULL;
    IDeckLinkVideoFrame3DExtensions*        threeDExtensions = NULL;
    void*					frameBytes;

    // Handle Video Frame
    if(videoFrame)
    {
        // If 3D mode is enabled we retreive the 3D extensions interface which gives.
        // us access to the right eye frame by calling GetFrameForRightEye() .
        if ( (videoFrame->QueryInterface(IID_IDeckLinkVideoFrame3DExtensions, (void **) &threeDExtensions) != S_OK) ||
            (threeDExtensions->GetFrameForRightEye(&rightEyeFrame) != S_OK))
        {
            rightEyeFrame = NULL;
        }

        if (threeDExtensions)
            threeDExtensions->Release();

        if (videoFrame->GetFlags() & bmdFrameHasNoInputSource)
        {
            fprintf(stderr, "Frame received (#%lu) - No input signal detected\n", frameCount);
        }
        else
        {
            const char *timecodeString = NULL;
            if (g_timecodeFormat != 0)
            {
                IDeckLinkTimecode *timecode;
                if (videoFrame->GetTimecode(g_timecodeFormat, &timecode) == S_OK)
                {
                    timecode->GetString(&timecodeString);
                }
            }

            fprintf(stderr, "%s: Frame received (#%lu) [%s] - %s - Size: %d x %d and %li bytes\n",
                m_videoFilePrefix,
                frameCount,
                timecodeString != NULL ? timecodeString : "No timecode",
                rightEyeFrame != NULL ? "Valid Frame (3D left/right)" : "Valid Frame",
                    videoFrame->GetRowBytes(),
                    videoFrame->GetHeight(),
                videoFrame->GetRowBytes() * videoFrame->GetHeight());

            //IDeckLinkVideoConversion::ConvertFrame(videoFrame,)

            if (timecodeString)
                free((void*)timecodeString);

            snprintf(videoOutputFile, sizeof(videoOutputFile), "%s_%lu", m_videoFilePrefix, frameCount);

            if (videoOutputFile != NULL)
            {
                videoFrame->GetBytes(&frameBytes);
                //IplImage *ipl = cvCreateImageHeader(cvSize(videoFrame->GetRowBytes(), videoFrame->GetHeight()),
                                                    //IPL_DEPTH_8U,1);
                //write(videoOutputFile, frameBytes, videoFrame->GetRowBytes() * videoFrame->GetHeight());

                if (rightEyeFrame)
                {
                    rightEyeFrame->GetBytes(&frameBytes);
                    //write(videoOutputFile, frameBytes, videoFrame->GetRowBytes() * videoFrame->GetHeight());
                }
            }
        }

        if (rightEyeFrame)
            rightEyeFrame->Release();

        frameCount++;

        if (g_maxFrames > 0 && frameCount >= g_maxFrames)
        {
            m_HDC->capturefinished();
        }
    }

    // Handle Audio Frame

    return S_OK;
}

HRESULT HDCamera::HDDelegate::VideoInputFormatChanged(BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *mode, BMDDetectedVideoInputFormatFlags)
{
    return S_OK;
}

void HDCamera::capturefinished()
{
    pthread_cond_signal(&sleepCond);
}
